#include "minet_socket.h"
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>

#define BUFSIZE 1024
#define FILENAMESIZE 100

int handle_connection(int sock);

int main(int argc, char * argv[]) {
    int server_port = -1;
    int rc          =  0;
    int sock        = -1;
	int acceptor_socket = -1;
    struct sockaddr_in * saddr;

    /* parse command line args */
    if (argc != 3) {
		fprintf(stderr, "usage: http_server1 k|u port\n");
		exit(-1);
    }

    server_port = atoi(argv[2]);

    if (server_port < 1500) {
		fprintf(stderr, "INVALID PORT NUMBER: %d; can't be < 1500\n", server_port);
		exit(-1);
    }

    /* initialize minet */
    if (toupper(*(argv[1])) == 'K') {
        minet_init(MINET_KERNEL);
    } else if (toupper(*(argv[1])) == 'U') {
        minet_init(MINET_USER);
    } else {
        fprintf(stderr, "First argument must be k or u\n");
        exit(-1);
    }

	/* make socket */
    if ((acceptor_socket = minet_socket(SOCK_STREAM)) < 0) {
		fprintf(stderr, "Failed on minet_socket.\n");
		exit(-1);
	}

    /* set server address*/
    saddr = (sockaddr_in*)malloc(sizeof(sockaddr_in));
    memset(saddr, 0, sizeof(sockaddr_in));
    saddr->sin_family = AF_INET;
    saddr->sin_port = htons(server_port);
    saddr->sin_addr.s_addr = INADDR_ANY;

    /* bind listening socket */
	if ((minet_bind(acceptor_socket, saddr)) < 0) {
		fprintf(stderr, "Failed on minet_bind.\n");
		exit(-1);
	}

    /* start listening */
	if ((minet_listen(acceptor_socket, 5)) < 0) {
		fprintf(stderr, "Failed on minet_listen.\n");
		exit(-1);
	}	

    /* connection handling loop: wait to accept connection */
	while (1) {
		/* handle connections */
		if((sock = minet_accept(acceptor_socket, NULL)) < 0) {
			fprintf(stderr, "Failed on minet_accept.\n");
			exit(-1);
		}
		rc = handle_connection(sock);
    }

	/* unreachable? */	
	free(saddr);
	minet_deinit();
	return rc;
}

int handle_connection(int sock) {
    bool ok = false;
	char * buffer = (char *)malloc(BUFSIZE);
	char * filename = (char *)malloc(FILENAMESIZE);

    char * ok_response_f = "HTTP/1.0 200 OK\r\n"	\
	"Content-type: text/plain\r\n"					\
	"Content-length: %d \r\n\r\n";
 
    char * notok_response = "HTTP/1.0 404 FILE NOT FOUND\r\n"	\
	"Content-type: text/html\r\n\r\n"							\
	"<html><body bgColor=black text=white>\n"					\
	"<h2>404 FILE NOT FOUND</h2>\n"								\
	"</body></html>\n";
    
    /* first read loop -- get request and headers */
    memset(buffer, 0, BUFSIZE);
	memset(filename, 0, FILENAMESIZE);
	if ((minet_read(sock, buffer, BUFSIZE-1)) <= 0) {
		fprintf(stderr, "Failed on minet_read.\n");
		exit(-1);
	}

    /* parse request to get file name */
    /* Assumption: this is a GET request and filename contains no spaces */
	int filenamelength = 0;
	for(int i=4; i<strlen(buffer); i++) {
		if(buffer[i] == ' ') {
			break;
		}
		filenamelength++;
	}
	strncpy(filename, &buffer[4], filenamelength);

	/* check for '/' at the beginning of filename */
	if(filename[0] == '/') {
		memmove(filename, filename+1, strlen(filename));
	}

    /* try opening the file */
	FILE * req_file = NULL;
	req_file = fopen(filename,"r");
	if(req_file == NULL)
		ok = false;
	else
		ok = true;

    /* send response */
    if (ok) {
		/* send headers */
		if(minet_write(sock, ok_response_f, strlen(ok_response_f)) <= 0) {
			fprintf(stderr, "Failed on minet_write ok_response.\n");
			exit(-1);
		}
		/* send file */
		memset(buffer, 0, BUFSIZE);
		fgets(buffer, BUFSIZE, req_file);
		while(!feof(req_file)) {
			minet_write(sock, buffer, strlen(buffer));
			fgets(buffer, BUFSIZE, req_file);
		}
    } else {
		// send error response
		if(minet_write(sock, notok_response, strlen(ok_response_f)) <= 0) {
            fprintf(stderr, "Failed on minet_write notok_response.\n");
            exit(-1);
        }
    }
    
    /* close socket and free space */
	minet_close(sock);
	free(buffer);
	free(filename);  	
	
    if (ok) {
		return 0;
    } else {
		return -1;
    }
}
